package com.easylinkin.linkappapi.listener;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import com.easylinkin.linkappapi.common.model.RequestModel;
import com.easylinkin.linkappapi.common.utils.DateUtil;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.device.mapper.DeviceMapper;
import com.easylinkin.linkappapi.device.service.DeviceService;
import com.easylinkin.linkappapi.deviceattributestatus.entity.DeviceAttributeStatus;
import com.easylinkin.linkappapi.deviceattributestatus.service.DeviceAttributeStatusService;
import org.junit.Test;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.codec.SerializationCodec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * <p> 设备监控页面的监听</p>
 *
 * @author TongJie
 * @since 2020/9/23 12:06
 */
@ServerEndpoint("/deviceMonitorListener/{tenantId}/{userId}")
@Component
public class DeviceMonitorListener extends Listener  {
    @Value("${linkapp.openReceiving:true}")
    private Boolean openReceiving;
    private static final Logger LOGGER = LoggerFactory.getLogger(DeviceMonitorListener.class);
    private static CopyOnWriteArraySet<DeviceMonitorListener> webSocketSet = new CopyOnWriteArraySet<>();
    private static DeviceMapper deviceMapper;
    private static DeviceService deviceService;
//    private static RedisUtil redisUtil;
    private static DeviceAttributeStatusService deviceAttributeStatusService;
    private RequestModel<Device> requestModel;

    @Resource
    private RedissonClient redisson;
    public static String WS_DEVICEMONITOR_LISTEN = "WS_DEVICEMONITOR_LISTEN";
    private RTopic topic;



    @Override
    @OnOpen
    public void onOpen(Session session, @PathParam("tenantId") String tenantId, @PathParam("userId") String userId) {
        init(session, tenantId, userId);
        // 加入set中
        webSocketSet.add(this);
    }

    @Override
    @OnMessage
    public void onMessage(String message, Session session) {
        LOGGER.info("收到通知会话消息,message:{},用户id:{}", message, this.getUserId());
        if(StringUtils.isEmpty(message)){
            return;
        }
        JSONObject jsonObject = JSONObject.parseObject(message);
        if(jsonObject == null || jsonObject.isEmpty()){
            return;
        }
        Page page = jsonObject.getObject("page", Page.class);
        Device device =jsonObject.getObject("customQueryParams",Device.class);
        if(this.requestModel == null){
            this.requestModel=new RequestModel<>();
        }
         this.requestModel.setCustomQueryParams(device);
         this.requestModel.setPage(page);
        String msg = message(this.requestModel.getPage(),this.requestModel.getCustomQueryParams(), this.getTenantId(),null);
        if(StringUtils.isEmpty(msg)){
            return;
        }
        this.sendMessage(msg);
    }

    private String message(Page page,Device device,String tenantId,String deviceCode){
        if(StringUtils.isEmpty(tenantId)){
            return null;
        }
        if(device == null){
            device=new Device();
        }
        //设备
        device.setTenantId(tenantId);
        List<Device> devices =null;
        Object result=null;
        if(page !=null){
            IPage<Device> monitorDevices = deviceService.getMonitorPage(page, device);
            if(monitorDevices == null){
                return  null;
            }
            devices=monitorDevices.getRecords();
            result=monitorDevices;
        }else{
            devices=deviceMapper.getMonitorDevices(device);
            result=devices;
            for (Device device1 : devices) {
                List<DeviceAttributeStatus> deviceAttributeList = device1.getDeviceAttributeStatusList();
                deviceAttributeList = deviceAttributeStatusService.getFormatDeviceAttributeStatusList(deviceAttributeList);
                device1.setDeviceAttributeStatusList(deviceAttributeList);
            }
        }
//        Device countDevice=new Device();
//        countDevice.setTenantId(device.getTenantId());
//        //获取数量
//        Map<String, Object> countDeviceByOnlineState = deviceService.countDeviceByOnlineState(countDevice);
//        Map<String, Object> countDeviceByStatus = deviceService.countDeviceByStatus(countDevice);
//        //获取类型统计
//        List<Map<String, Object>> statisticsExistDeviceByType = deviceService.getStatisticsExistDeviceByType(countDevice);
//        HashMap<String,Object> map=new HashMap<>();
//        map.put("countDeviceByOnlineState",countDeviceByOnlineState);
//        map.put("countDeviceByStatus",countDeviceByStatus);
//        map.put("getStatisticsExistDeviceByType",statisticsExistDeviceByType);
//        map.put("getMonitorPage",result);
        String msg = JSONObject.toJSONString(result);
        return  msg;
    }

    /**
     * 连接关闭调用的方法
     */
    @Override
    @OnClose
    public void onClose() {
        LOGGER.info("通知关闭连接,用户id:{}", getUserId());
        // 从set中删除
        webSocketSet.remove(this);
    }

    /**
     * 开启监听
     */
    @PostConstruct
    void openReceiving() {
        if (!openReceiving) {
            return;
        }
        topic = redisson.getTopic(WS_DEVICEMONITOR_LISTEN, new SerializationCodec());
        LOGGER.info("监听ws成功：{}", topic);
        topic.addListener(Device.class, (charSequence, device) -> {
            send(device);
        });
    }

    public void sendNotice(Device device) {
//        redis 发广播
        try {
            topic.publish(device);
        } catch (Exception e) {
            LOGGER.error("sendNotice失败：", e);
        }

//        String key = WS_DEVICEMONITOR_LISTEN + UUID.randomUUID();
//        redisUtil.set(key+ "_param", device, 15);
//        //        10毫秒过期
//        redisUtil.setExpiredMilliseconds(key, "", 10);
    }

    //    解决 fastjson toJSON方法日期类型字段 由时间戳转换成自定义类型格式的问题
    @Test
    public void test() {
        Device d = new Device();
        d.setLastPushTime(new Date());
        String msg = JSONObject.toJSONString(d);
        System.out.println(msg);
//        String ss = JSON.toJSONStringWithDateFormat(d, "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteDateUseDateFormat);
        String ss = JSON.toJSONStringWithDateFormat(d, DateUtil.DATE_TIME_FORMAT_DEFAULT, SerializerFeature.WriteDateUseDateFormat);
        System.out.println(ss);
    }

    public void send(Device device) {
        if(device == null || StringUtils.isEmpty(device.getCode()) || StringUtils.isEmpty(device.getTenantId())){
            return;
        }
        Page page = new Page(1, 1);
        IPage<Device> monitorDevices = deviceService.getMonitorPage(page, device);
        if(monitorDevices == null || monitorDevices.getRecords() == null || monitorDevices.getRecords().size()<=0){
            return;
        }
        device = monitorDevices.getRecords().get(0);
//        String msg = JSONObject.toJSONString(device);
        //    解决 fastjson toJSON方法日期类型字段 由时间戳转换成自定义类型格式的问题
        String msg = JSON.toJSONStringWithDateFormat(device, DateUtil.DATE_TIME_FORMAT_DEFAULT, SerializerFeature.WriteDateUseDateFormat);
        for (DeviceMonitorListener listener : webSocketSet) {
            if(listener.requestModel == null || listener.requestModel.getCustomQueryParams() == null || listener.requestModel.getCustomQueryParams().getCodes() == null){
                if(listener.getTenantId() != null && listener.getTenantId().equals(device.getTenantId())){
                    listener.sendMessage(msg);
                }
            }else{
            Device customQueryParams = listener.requestModel.getCustomQueryParams();
            if (listener.getTenantId() != null && listener.getTenantId().equals(device.getTenantId())
                    && (StringUtils.isEmpty(customQueryParams.getMoniterCommonQuery())  || customQueryParams.getMoniterCommonQuery().equals(device.getCode())
                        || customQueryParams.getMoniterCommonQuery().equals(device.getDeviceUnitCode())
                        || customQueryParams.getMoniterCommonQuery().equals(device.getName())
                        || customQueryParams.getMoniterCommonQuery().equals(device.getDeviceTypeName()))
                    && (StringUtils.isEmpty(customQueryParams.getAreaPath()) || device.getAreaPath().startsWith(customQueryParams.getAreaPath()))
                    && (StringUtils.isEmpty(customQueryParams.getDeviceTypeId()) || StringUtils.isEmpty(device.getDeviceTypeId()) || customQueryParams.getDeviceTypeId().equals(device.getDeviceTypeId()))
                    && (customQueryParams.getCodes() == null || customQueryParams.getCodes().contains(device.getCode()))) {
                String message = message(listener.requestModel.getPage(),customQueryParams, listener.getTenantId(),device.getCode());
                if(!StringUtils.isEmpty(message)){
                    listener.sendMessage(message);
                }
            }
            }

//            Device customQueryParams = listener.requestModel.getCustomQueryParams();
//            if (listener.getTenantId() != null && listener.getTenantId().equals(device.getTenantId())
//                    && (StringUtils.isEmpty(customQueryParams.getMoniterCommonQuery())  || customQueryParams.getMoniterCommonQuery().equals(device.getCode())
//                        || customQueryParams.getMoniterCommonQuery().equals(device.getDeviceUnitCode())
//                        || customQueryParams.getMoniterCommonQuery().equals(device.getName())
//                        || customQueryParams.getMoniterCommonQuery().equals(device.getDeviceTypeName()))
//                    && (StringUtils.isEmpty(customQueryParams.getAreaPath()) || device.getAreaPath().startsWith(customQueryParams.getAreaPath()))
//                    && (StringUtils.isEmpty(customQueryParams.getDeviceTypeId()) || StringUtils.isEmpty(device.getDeviceTypeId()) || customQueryParams.getDeviceTypeId().equals(device.getDeviceTypeId()))
//                    && (customQueryParams.getCodes() == null || customQueryParams.getCodes().contains(device.getCode()))) {
//                String message = message(listener.requestModel.getPage(),customQueryParams, listener.getTenantId(),device.getCode());
//                if(!StringUtils.isEmpty(message)){
//                    listener.sendMessage(message);
//                }
//            }
        }
    }

    @Resource
    public  void setDeviceMapper(DeviceMapper deviceMapper) {
        DeviceMonitorListener.deviceMapper = deviceMapper;
    }
    @Resource
    public  void setDeviceAttributeStatusService(DeviceAttributeStatusService deviceAttributeStatusService) {
        DeviceMonitorListener.deviceAttributeStatusService = deviceAttributeStatusService;
    }
    @Resource
    public  void setDeviceService(DeviceService deviceService) {
        DeviceMonitorListener.deviceService = deviceService;
    }
//    @Resource
//    public  void setRedisUtil(RedisUtil redisUtil) {
//        DeviceMonitorListener.redisUtil = redisUtil;
//    }
}